
global _main

section .text 
_main:
	._init: ;初始化寄存器		
		;init info
		MOV 	AX,strmsg
		MOV 	BX,DS
		CAll 	showmsg
	
	;尝试保护模式
		 ;创建0#描述符，它是空描述符，这是处理器的要求
		 MOV AX,0
		 MOV ES,AX;
		 MOV BX,0x200;
		 
		 ;0号GDT
         mov dword [bx+0x00],0x00
         mov dword [bx+0x04],0x00  
		;32 addr   =0x0020000~
			
			;对应0x[00]409800
				;段基地址 31~24
			;对应0x00[4]09800
				;g=1;//段粒度 4k一个段
				;d/b=1; 1  32模式
				;l=0 64位模式
				;avl=0；custom
			;对应0x004[0]9800
				;段界19~16  
			;对应0x0040[9]800
				;p =1 段存在
				;DPL=00b 3级别最低，0特权级别
				;s=1 系统段 数据段
			;对应0x00409[8]00
				;TYPE 要查表构造 x位可以操作系统用
				;100xb 代码:只执行
				;101xb 代码;执行&读
				;110xb 代码;执行&依存
				;111xb 代码;执行&依存&读
				;000xb 数据;只读
				;001xb 数据;读&写
				;010xb 数据;读&扩展
				;011xb 数据;读&写&扩展
			;对应0x004098[00]
				;段基地址 23~16
			;对应0x[7c00]01ff	
				;段基地址 15~0
			;对应0x7c00[01ff]
				;段界限	15~0
				
			;所以段基地址= 0x00007c00
			;段界        = 0x001ff 20bit
		 ;创建#1描述符，保护模式下的代码段描述符
         mov dword [bx+0x08],0x940001ff     
         mov dword [bx+0x0c],0x00409800 
         ;创建#2描述符，保护模式下的数据段描述符（文本模式下的显示缓冲区） 
         mov dword [bx+0x10],0x8000ffff     
         mov dword [bx+0x14],0x0040920b     
         ;创建#3描述符，保护模式下的堆栈段描述符
         mov dword [bx+0x18],0x00007a00
         mov dword [bx+0x1c],0x00409600

         mov word [DS:gdt_size],31  ;描述符表的界限（总字节数减一）   
		 mov dword [DS:gdt_addr],0x9600;
		 
		 lgdt [DS:gdt_size];//一个地址，从该地址开始读6字节 前两字节是GDT表的字节数-1，后四字节是GDT表的绝对地址
		 in al,0x92                         ;南桥芯片内的端口 
         or al,0000_0010B
         out 0x92,al                        ;打开A20

         cli                                ;保护模式下中断机制尚未建立，应 
                                            ;禁止中断 
         mov eax,cr0
         or eax,1
         mov cr0,eax                        ;设置PE位
      
         ;以下进入保护模式... ...
		 ;此时段选择器的意义已经不同
		 ;[15~3bit]第几个段，这里选1 就是配置为9400 那个
		 ;[2 bit]TI=0 GDP地址，否则是LDT地址
		 ;[1~0bit]RPL 00b 段的级别
         jmp  dword 0x0008:func32        ;16位的描述符选择子：32位偏移
    
showmsg: ;void showmsg(BX:AX addr) ;AX =word 16bit AH AL 是他的8bit 高低位 EAX 是dword 32bit
		 MOV 		ES,BX;
		 MOV		SI,AX;//把参数1拉进SI
		 ; MOV 		CX,BX;
		 ; ;ifCX==0 CX=255
		 ; CMP		CX,0
		 ; JNC		showmsg.putloop
		 ; MOV		CX,0x1ff
	 showmsg.putloop:
		 MOV		AL,[ES:SI]		;AL = *SI  []的意思就是把SI作为地址，取这个内存位置的值，所有用到地址的时候默认地址都是
		 ;AL,[DS:SI]  从DS段读取
	    

		 ADD		SI,1			; 给SI加1	SI++
		 CMP		AL,0			; CMP 指令有隐藏的输出 Flags.ZF 会变成1
		 JZ			showmsg.return				; JE指令有隐藏的输入 if(Flags.ZF==1) JMP
		 
		
		 MOV		AH,0x0e			; 显示一个文字
		 MOV		BX,15			; 指定字符颜色
		 INT		0x10			; 调用显卡BIOS	INT隐藏的输入输出众多，根据调用的功能不同差距很大，前面的这些都是他的输入
			; ;INT10 输出文字使用四个输入 BH =0 AH =0x0e AL =字符 BX =颜色  显示文字
		 ; SUB		CX,1			; 限制长度逻辑
		 ; CMP		CX,0
		 ; JZ 		showmsg.return
		 JMP		showmsg.putloop
	 showmsg.return:		
	 
		 RET;	
                                        ;清流水线并串行化处理器 
         [bits 32] 


func32:
         mov cx,00000000000_10_000B         ;加载数据段选择子(0x10)
         mov Es,cx

         ;以下在屏幕上显示"Protect mode OK." 
         mov byte [Es:80*24+0x00],'P'  
         mov byte [Es:80*24+0x02],'r'
         mov byte [Es:80*24+0x04],'o'
         mov byte [Es:80*24+0x06],'t'
         mov byte [Es:80*24+0x08],'e'
         mov byte [Es:80*24+0x0a],'c'
         mov byte [Es:80*24+0x0c],'t'
         mov byte [Es:80*24+0x0e],' '
         mov byte [Es:80*24+0x10],'m'
         mov byte [Es:80*24+0x12],'o'
         mov byte [Es:80*24+0x14],'d'
         mov byte [Es:80*24+0x16],'e'
         mov byte [Es:80*24+0x18],' '
         mov byte [Es:80*24+0x1a],'O'
         mov byte [Es:80*24+0x1c],'K'	 
fin:
		HLT						; 让CPU停止，等待指令 sleep
		JMP		fin				; 无限循环


section .data
	strmsg:
		db	'this is boot file 004',0x0d,0x0a,0x00
	gdt_size:
		dw 0
	gdt_addr:
		dd 0